package com.lizemin.mybatis.annotation;

import cn.hutool.core.util.StrUtil;
import com.lizemin.mybatis.constants.SqlConstants;
import com.lizemin.mybatis.entity.MapperSql;
import com.lizemin.mybatis.entity.ParamValue;
import com.lizemin.mybatis.sqlHandler.*;

import javax.sql.DataSource;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author lzm
 * @date 2025/5/18 21:46
 * @description
 */
public class MybatisInvocationHandler implements InvocationHandler {

    private final Map<String, MapperSql> sqlMap;

    private final DataSource dataSource;

    public MybatisInvocationHandler(Map<String, MapperSql> sqlMap, DataSource dataSource) {
        this.sqlMap = sqlMap;
        this.dataSource = dataSource;
    }

    /**
     * 执行方法
     *
     * @param proxy  代理对象
     * @param method 方法
     * @param args   方法参数
     * @return 方法返回值
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        String name = method.getName();
        MapperSql mapperSql = sqlMap.get(name);
        if (Objects.isNull(mapperSql)) {
            throw new RuntimeException("未找到对应的sql语句");
        }
        int parameterCount = method.getParameterCount();
        if (args != null && parameterCount != args.length) {
            throw new RuntimeException("参数个数不匹配");
        }
        HashMap<String, ParamValue> paramValueMap = new HashMap<>();
        Class<?>[] parameterTypes = method.getParameterTypes();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        ArrayList<String> paramNames = new ArrayList<>();
        for (Annotation[] parameterAnnotation : parameterAnnotations) {
            for (Annotation annotation : parameterAnnotation) {
                if (annotation instanceof SqlParam) {
                    SqlParam sqlParam = (SqlParam) annotation;
                    String paramName = sqlParam.value();
                    if (StrUtil.isBlank(paramName)) {
                        throw new RuntimeException("参数名不能为空");
                    }
                    paramNames.add(paramName);
                }
            }
        }
        for (int i = 0; i < parameterCount; i++) {
            ParamValue paramValue = new ParamValue();
            String paramName = paramNames.get(i);
            Object value = args[i];
            paramValue.setValue(value);
            paramValue.setType(parameterTypes[i]);
            paramValueMap.put(paramName, paramValue);
        }
        Class<?> returnType = method.getReturnType();
        String type = mapperSql.getType();
        SqlHandler handler;
        switch (type) {
            case SqlConstants.INSERT:
                handler = new InsertSqlHandler(dataSource);
                break;
            case SqlConstants.UPDATE:
                handler = new UpdateSqlHandler(dataSource);
                break;
            case SqlConstants.DELETE:
                handler = new DeleteSqlHandler(dataSource);
                break;
            case SqlConstants.SELECT:
                handler = new SelectSqlHandler(dataSource);
                break;
            default:
                throw new RuntimeException("不支持的操作类型");
        }
        return handler.handle(mapperSql, paramValueMap, returnType);
    }

}
